package unused;


import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.security.ProtectionDomain;
import java.util.*;

/**
 *
 */
public class UnusedPlugin {

    public static Class[] allClass;

    public static String main(String[] args) throws Exception {

        // 获取所有jar包
        Set<String> jars = getJars();
        int allJarSize = jars.size();
        // 获取所有class
        Class[] classes = getLoadedClasses();

        for (Class clazz : classes) {
            // 找到class对应的jar包
            String jar = Optional.of(clazz).map(Class::getProtectionDomain).map(ProtectionDomain::getCodeSource).map(CodeSource::getLocation).map(URL::toString).orElse(null);
            if (jars.contains(jar)) {
                jars.remove(jar); //有类加载过,则移除.最后留下来的就是unused
            }
        }
        // 写入文件里
        String fileName = "unused-jar.lst";
        File file = new File(fileName);
        writeFile(jars, file);
        String ret = "一共 " + allJarSize + " 个jar , " + jars.size() + " 个unused jar\n" + "详情见: " + file.getCanonicalPath();
        return ret;
    }

    private static void writeFile(Set<String> jars, File file) throws IOException {
        Writer writer = new FileWriter(file);
        jars.stream().sorted().forEach(jar -> {
            try {
                writer.write(jar);
                writer.write("\n");
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        });
        writer.close();
    }

    private static Set<String> getJars() {
        Set<ClassLoader> loaders = getClassLoaders();
        Set<String> jars = new HashSet<>();
        for (ClassLoader loader : loaders) {
            String loaderName = loader.getClass().getName();
            if ("jdk.internal.loader.ClassLoaders$AppClassLoader".equals(loaderName)) {

                Object ucp = get(loader, "ucp");
                List<?> urlList = (List<?>) get(ucp, "path");

                urlList.stream().map(Object::toString).forEach(jars::add);
            } else if ("jdk.internal.loader.ClassLoaders$PlatformClassLoader".equals(loaderName)) {

            } else if (loader instanceof URLClassLoader) {
                URLClassLoader urlClassLoader = (URLClassLoader) loader;
                URL[] urLs = urlClassLoader.getURLs();
                Arrays.stream(urLs).map(URL::toString).forEach(jars::add);
            } else { // todo
                System.out.println("暂时不支持的loader:" + loader);
            }
        }
        return jars;
    }

    public static Object get(Object o, String name) {
        try {
            Class clz = o.getClass();
            Field field = ReflectUtils.getField(clz, name);
            field.setAccessible(true);
            return field.get(o);
        } catch (Exception e) {
//            System.out.println(o + " - " + name);
            return UnsafeUtils.get(o, name);
        }
    }

    private static Set<ClassLoader> getClassLoaders() {
        Set<ClassLoader> loaders = new HashSet<>();
        Class[] allLoadedClasses = getLoadedClasses();
        for (Class clazz : allLoadedClasses) {
            ClassLoader classLoader = clazz.getClassLoader();
            if (classLoader != null) {
                loaders.add(classLoader);
            }
        }
//        for (ClassLoader loader : loaders) {
//            System.out.println(loader);
//        }
        return loaders;
    }

    private static Class[] getLoadedClasses() {
        return allClass;
    }
}
